package jay9downloader;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.text.DecimalFormat;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

/**
 * Thread for downloading the file at the supplied url.
 * @author Jonas
 */
public  class       DownloadUrl
        extends     Thread
        implements  GUIUpdaterInterface, ChangeListener {

    private static final long MEGABYTE = 1024L * 1024L;
    private static final int BUFFER_SIZE = 4096;
    public static int SLEEPTIMER = 1000;
    private static final int[] sleepTranslatesTo = {
                    50, 100, 250, 500, 750, 1000, 1500, 2000, 3000, 4000, 5000};
    private URL u;
    private InputStream is = null;
    private DataInputStream dis;
    private DataOutputStream dos;
    private File file;
    private String s;
    private Byte b;
    private int size = 0;
    private URLConnection conn;
    private DecimalFormat df;
    private DecimalFormat percentageFormatter;
    private String url;
    private String destination;
    private JProgressBar jProgressBar;
    private JGraphPanel jgp;
    private GUIUpdaterThread progressUpdater;
    private boolean run;
    private JButton downloadButton;
    private JButton stopButton;
    private Video associatedVideo;

    public DownloadUrl(String url, String destination, Video video) throws IOException {
        this.url = url;
        this.destination = destination;
        this.run = true;
        this.associatedVideo = video;
        this.percentageFormatter = new DecimalFormat("000");
    }

    public int getProgress() {
        return dos.size();
    }

    public String getProgressPercentage() {
        return df.format(((float) dos.size() / (float) size) * 100f);
    }

    public int getProgressPercentageAsInt() {
        return Integer.parseInt(percentageFormatter.format(((float)dos.size()/this.size)*100f));
    }

    public static long toMiB(long bytes) {
        return bytes / MEGABYTE;
    }

    private String getPtrogressString() {
        return (0 + "% " + 0 + "MiB of " + DownloadUrl.toMiB(this.size) + "MiB " + 0 + "KiB/s");
    }

    @Override
    public synchronized void run() {
        super.run();
        //-----------------------------------------------------//
        //  Step 1:  Start creating a few objects we'll need.
        //-----------------------------------------------------//



        url = (!url.contains("http://")) ? "http://" + url : url;
        String[] s = this.url.split("[\\p{Punct}]");
        this.destination = this.destination + "." + s[s.length-1];
        file = new File(this.destination);
        df = new DecimalFormat("0.00");

        try {
            System.out.println("Starting download of " + url);

            //------------------------------------------------------------//
            // Step 2:  Create the URL.                                   //
            //------------------------------------------------------------//
            // Note: Put your real URL here, or better yet, read it as a  //
            // command-line arg, or read it from a file.                  //
            //------------------------------------------------------------//

            u = new URL(url);
            conn = u.openConnection();
            size = conn.getContentLength();

            //----------------------------------------------//
            // Step 3:  Open an input stream from the url.  //
            //----------------------------------------------//

            is = u.openStream();         // throws an IOException

            //-------------------------------------------------------------//
            // Step 4:                                                     //
            //-------------------------------------------------------------//
            // Convert the InputStream to a buffered DataInputStream.      //
            // Buffering the stream makes the reading faster; the          //
            // readLine() method of the DataInputStream makes the reading  //
            // easier.                                                     //
            //-------------------------------------------------------------//

            dis = new DataInputStream(new BufferedInputStream(is));
            dos = new DataOutputStream(new FileOutputStream(file));

            //------------------------------------------------------------//
            // Step 5:                                                    //
            //------------------------------------------------------------//
            // Now just read each record of the input stream, and print   //
            // it out.  Note that it's assumed that this problem is run   //
            // from a command-line, not from an application or applet.    //
            //------------------------------------------------------------//

            byte[] buffer = new byte[BUFFER_SIZE];
            int length = 0;
            progressUpdater = new GUIUpdaterThread(this);
            progressUpdater.start();
            associatedVideo.setStatus(Video.Status.DOWNLOADING);
            associatedVideo.setDownloadedTo(destination);
            while ((dis != null) && ((length = dis.read(buffer)) != -1)) {
                dos.write(buffer, 0, length);
            }
            associatedVideo.setStatus(Video.Status.DONE);
            
        } catch (MalformedURLException mue) {

            System.out.println("Ouch - a MalformedURLException happened.");
            mue.printStackTrace();

        } catch (IOException ioe) {
            JOptionPane.showMessageDialog(null, "Please enter an existing directory.", "Directory not found", JOptionPane.ERROR_MESSAGE);
            System.out.println("Oops- an IOException happened.");
            ioe.printStackTrace();

        } finally {
            progressUpdater.setRun(false);
            this.run = false;
            associatedVideo.setStatus(Video.Status.DONE);
            System.out.println("Finished download of " + url + "\tSaved to " + file.getAbsolutePath());
            //---------------------------------//
            // Step 6:  Close the InputStream  //
            //---------------------------------//

            try {
                is.close();
                dos.flush();
                dos.close();
            } catch (IOException ioe) {
                // just going to ignore this one
            }

        } // end of 'finally' clause

    }

    public void updateGui() {
        long currentTime = 0;
        int beforeBytes = 0;
        int bytesPerSec = 0;
        do {
            currentTime = System.currentTimeMillis();
            associatedVideo.setDownloadProgress(this.getProgressPercentageAsInt());
            beforeBytes = this.getProgress();
            try {
                Thread.sleep(SLEEPTIMER);
            } catch (InterruptedException ex) {
            }
            bytesPerSec = (this.getProgress() - beforeBytes) / SLEEPTIMER;
        } while (run);
    }

    public void stateChanged(ChangeEvent e) {
        DownloadUrl.SLEEPTIMER = sleepTranslatesTo[((JSlider)e.getSource()).getValue()];
    }
}
